﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Joy.Erp.BasicArchives.Core;
using Joy.Erp.BasicArchives.ItemMasters;
using Joy.Erp.Ufida.Core;
using Microsoft.Extensions.Logging;

namespace Joy.Erp.Ufida.ItemMasters
{
    public class BomMasterSyncAppService : UfidaAppService, IBomMasterSyncAppService
    {
        protected IBomMasterRepository BomMasterRepository =>
            LazyServiceProvider.LazyGetRequiredService<IBomMasterRepository>();
        protected IItemMasterRepository ItemMasterRepository =>
            LazyServiceProvider.LazyGetRequiredService<IItemMasterRepository>();
        protected IUnitGroupAppService UnitGroupAppService =>
            LazyServiceProvider.LazyGetRequiredService<IUnitGroupAppService>();
        protected IBomMasterUfidaAppService BomMasterUfidaAppService =>
            LazyServiceProvider.LazyGetRequiredService<IBomMasterUfidaAppService>();

        public async Task<AnalysisDto> AnalyzeAsync()
        {
            var analysisDto = new AnalysisDto();
            analysisDto.Id = typeof(BomMaster).FullName;

            var u9list = await BomMasterUfidaAppService.GetAllAsync();
            var u9Ids = u9list.Select(x => x.MasterID.ToString()).Distinct().ToHashSet();
            analysisDto.U9Count = u9Ids.Count;

            var pmcQuery = await BomMasterRepository.GetQueryableAsync();
            analysisDto.Count = await AsyncExecuter.CountAsync(pmcQuery.Where(x => !x.IsDeleted));

            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );

            analysisDto.AsyncCount = syncedSourceKeys.Count(key => u9Ids.Contains(key));
            analysisDto.UnasyncCount = analysisDto.U9Count - analysisDto.AsyncCount;
            analysisDto.SelfCount = analysisDto.Count - analysisDto.AsyncCount;

            return analysisDto;
        }

        public async Task<List<long>> GetUnasyncIds()
        {
            var u9list = await BomMasterUfidaAppService.GetAllAsync();
            var u9Ids = u9list.Select(x => x.MasterID).Distinct().ToList();

            var pmcQuery = await BomMasterRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );

            var syncedSourceKeySet = new HashSet<string>(syncedSourceKeys);
            var unasyncIds = u9Ids
                .Where(id => !syncedSourceKeySet.Contains(id.ToString()))
                .ToList();

            return unasyncIds;
        }

        public async Task<int> CreateByIds‌Async(long[] ids)
        {
            if (ids == null || ids.Length == 0)
                return 0;

            var pmcQuery = await BomMasterRepository.GetQueryableAsync();
            var idStrings = ids.Select(id => id.ToString()).ToList();
            var existingSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x =>
                        idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                    )
                    .Select(x => x.SourceKey)
            );
            var existingSet = new HashSet<string>(existingSourceKeys);

            var needCreateIds = ids
                .Where(id => !existingSet.Contains(id.ToString()))
                .Distinct()
                .ToList();
            if (needCreateIds.Count == 0)
                return ids.Length;

            Logger.LogInformation(
                $"[批量同步-物料清单] 开始处理 {needCreateIds.Count} 条创建，总共 {ids.Length} 条（已存在 {existingSet.Count} 条）"
            );

            var allU9DataDict = new Dictionary<long, List<BomMasterUfidaDto>>();
            foreach (var id in needCreateIds)
            {
                try
                {
                    var items = await BomMasterUfidaAppService.GetLinesAsync(id);
                    if (items != null && items.Count > 0)
                    {
                        allU9DataDict[id] = items;
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-物料清单] 获取U9数据失败，Id: {id}");
                }
            }

            if (allU9DataDict.Count == 0)
                return existingSet.Count;

            var allItemMasterSourceKeys = new HashSet<string>();
            foreach (var items in allU9DataDict.Values)
            {
                if (items.Count > 0)
                {
                    allItemMasterSourceKeys.Add(items[0].MasterItemID.ToString());
                    foreach (var line in items)
                    {
                        allItemMasterSourceKeys.Add(line.ComponentItemID.ToString());
                    }
                }
            }

            var itemMasterCacheDict = await BatchLoadItemMasters(allItemMasterSourceKeys.ToList());
            var unitGroupIds = itemMasterCacheDict.Values
                .Select(x => x.UnitGroupId)
                .Where(id => id != Guid.Empty)
                .Distinct()
                .ToList();
            var unitGroupCacheDict = await BatchLoadUnitGroups(unitGroupIds);

            var entities = new List<BomMaster>();
            foreach (var kvp in allU9DataDict)
            {
                try
                {
                    var entity = BuildBomMasterEntity(
                        kvp.Key,
                        kvp.Value,
                        itemMasterCacheDict,
                        unitGroupCacheDict
                    );
                    if (entity != null)
                    {
                        entities.Add(entity);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-物料清单] 创建实体失败，Id: {kvp.Key}");
                }
            }

            var successCount = 0;
            if (entities.Count > 0)
            {
                using (
                    var uow = UnitOfWorkManager.Begin(
                        new Volo.Abp.Uow.AbpUnitOfWorkOptions(),
                        requiresNew: true
                    )
                )
                {
                    try
                    {
                        await BomMasterRepository.BulkInsertAsync(entities, autoSave: false);
                        await uow.CompleteAsync();
                        successCount = entities.Count;
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning(ex, $"[批量同步-物料清单] 批量插入失败，{ex.Message}");
                    }
                }
            }

            Logger.LogInformation(
                $"[批量同步-物料清单] 完成！成功创建 {successCount} 条，已存在 {existingSet.Count} 条，总计 {successCount + existingSet.Count} 条"
            );

            return successCount + existingSet.Count;
        }

        public async Task<List<long>> GetSyncedIds()
        {
            var pmcQuery = await BomMasterRepository.GetQueryableAsync();
            var syncedSourceKeys = await AsyncExecuter.ToListAsync(
                pmcQuery
                    .Where(x => !x.IsDeleted && x.SourceType == SourceConfig.SourceType)
                    .Select(x => x.SourceKey)
            );

            return syncedSourceKeys
                .Select(
                    key => long.TryParse(key, out var parsedId) ? (long?)parsedId : null
                )
                .Where(id => id.HasValue)
                .Select(id => id.Value)
                .ToList();
        }

        public async Task<int> UpdateByIdsAsync(long[] ids)
        {
            if (ids == null || ids.Length == 0)
                return 0;

            Logger.LogInformation($"[批量同步-物料清单] 开始处理 {ids.Length} 条更新/删除");

            var pmcQuery = await BomMasterRepository.WithDetailsAsync(x => x.Children);
            var idStrings = ids.Select(id => id.ToString()).ToList();
            var existingEntities = await AsyncExecuter.ToListAsync(
                pmcQuery.Where(x =>
                    idStrings.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );

            if (existingEntities.Count == 0)
            {
                Logger.LogWarning($"[批量同步-物料清单] 没有找到需要处理的记录");
                return 0;
            }

            var entityDict = existingEntities.ToDictionary(x => x.SourceKey, x => x);

            var allU9DataDict = new Dictionary<long, List<BomMasterUfidaDto>>();
            var entitiesToDelete = new List<BomMaster>();
            foreach (var id in ids)
            {
                if (!entityDict.ContainsKey(id.ToString()))
                {
                    continue;
                }

                try
                {
                    var items = await BomMasterUfidaAppService.GetLinesAsync(id);
                    if (items != null && items.Count > 0)
                    {
                        allU9DataDict[id] = items;
                    }
                    else
                    {
                        entitiesToDelete.Add(entityDict[id.ToString()]);
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"[批量同步-物料清单] 获取U9数据失败，Id: {id}");
                }
            }

            var entitiesToUpdate = new List<BomMaster>();
            if (allU9DataDict.Count > 0)
            {
                var allItemMasterSourceKeys = new HashSet<string>();
                foreach (var items in allU9DataDict.Values)
                {
                    if (items.Count > 0)
                    {
                        allItemMasterSourceKeys.Add(items[0].MasterItemID.ToString());
                        foreach (var item in items)
                        {
                            allItemMasterSourceKeys.Add(item.ComponentItemID.ToString());
                        }
                    }
                }

                var itemMasterCacheDict = await BatchLoadItemMasters(allItemMasterSourceKeys.ToList());
                var unitGroupIds = itemMasterCacheDict.Values
                    .Select(x => x.UnitGroupId)
                    .Where(id => id != Guid.Empty)
                    .Distinct()
                    .ToList();
                var unitGroupCacheDict = await BatchLoadUnitGroups(unitGroupIds);

                foreach (var kvp in allU9DataDict)
                {
                    if (!entityDict.TryGetValue(kvp.Key.ToString(), out var entity))
                    {
                        continue;
                    }

                    var u9Items = kvp.Value;
                    if (u9Items.Count == 0)
                    {
                        continue;
                    }

                    try
                    {
                        if (
                            !itemMasterCacheDict.TryGetValue(
                                u9Items[0].MasterItemID.ToString(),
                                out var masterItemDto
                            )
                        )
                        {
                            Logger.LogWarning(
                                $"[批量同步-物料清单] 未找到母件料品，SourceKey: {u9Items[0].MasterItemID}"
                            );
                            continue;
                        }

                        if (
                            !TryGetAuxiliaryUnitId(
                                masterItemDto.UnitGroupId,
                                u9Items[0].MasterUnit.ToString(),
                                unitGroupCacheDict,
                                out var masterUnitId
                            )
                        )
                        {
                            Logger.LogWarning(
                                $"[批量同步-物料清单] 未找到母件计量单位，SourceKey: {u9Items[0].MasterUnit}"
                            );
                            continue;
                        }

                        entity.Code = u9Items[0].MasterCode;
                        entity.BusinessDate = u9Items[0].BusinessDate ?? DateTime.Now.Date;
                        entity.DocumentStatus = ToDocumentStatus(u9Items[0].DocumentStatus);
                        entity.Version = u9Items[0].Version;
                        entity.SourceCreatedOn = GetSourceCreatedOn(u9Items);
                        entity.ItemMasterId = masterItemDto.Id;
                        entity.ItemCode = u9Items[0].MasterCode;
                        entity.ItemName = u9Items[0].MasterName;
                        entity.ItemSpec = u9Items[0].MasterSPECS;
                        entity.UseCount = u9Items[0].MasterUseCount;
                        entity.ParentCount = u9Items[0].MasterUseCount;
                        entity.UnitId = masterUnitId;
                        entity.LastModificationTime = Clock.Now;
                        entity.LastModifierId = CurrentUser.Id;

                        var existingChildrenDict = entity.Children.ToDictionary(x => x.SourceKey);
                        var processedKeys = new HashSet<string>();

                        foreach (var item in u9Items)
                        {
                            if (
                                !itemMasterCacheDict.TryGetValue(
                                    item.ComponentItemID.ToString(),
                                    out var componentItemDto
                                )
                            )
                            {
                                Logger.LogWarning(
                                    $"[批量同步-物料清单] 未找到子件料品，SourceKey: {item.ComponentItemID}"
                                );
                                continue;
                            }

                            if (
                                !TryGetAuxiliaryUnitId(
                                    componentItemDto.UnitGroupId,
                                    item.ComponentUnit.ToString(),
                                    unitGroupCacheDict,
                                    out var componentUnitId
                                )
                            )
                            {
                                Logger.LogWarning(
                                    $"[批量同步-物料清单] 未找到子件计量单位，SourceKey: {item.ComponentUnit}"
                                );
                                continue;
                            }

                            var sourceKey = item.ComponentID.ToString();
                            processedKeys.Add(sourceKey);

                            if (existingChildrenDict.TryGetValue(sourceKey, out var child))
                            {
                                child.LineNo = item.Sequence;
                                child.ItemMasterId = componentItemDto.Id;
                                child.ItemCode = item.ComponentCode;
                                child.ItemName = item.ComponentName;
                                child.ItemSpec = item.ComponentSPECS;
                                child.UseCount = item.ComponentUseCount;
                                child.ParentCount = item.ComponentParentCount;
                                child.UnitId = componentUnitId;
                                child.SourceCreatedOn = item.CreatedOn;
                                child.LastModificationTime = Clock.Now;
                                child.LastModifierId = CurrentUser.Id;
                                child.DocumentId = entity.Id;
                            }
                            else
                            {
                                var component = new BomComponent
                                {
                                    SourceType = SourceConfig.SourceType,
                                    SourceKey = sourceKey,
                                    SourceCreatedOn = item.CreatedOn,
                                    LineNo = item.Sequence,
                                    ItemMasterId = componentItemDto.Id,
                                    ItemCode = item.ComponentCode,
                                    ItemName = item.ComponentName,
                                    ItemSpec = item.ComponentSPECS,
                                    UseCount = item.ComponentUseCount,
                                    ParentCount = item.ComponentParentCount,
                                    UnitId = componentUnitId,
                                    DocumentId = entity.Id,
                                    CreationTime = Clock.Now,
                                    CreatorId = CurrentUser.Id,
                                };
                                component.SetId(GuidGenerator.Create());
                                entity.Children.Add(component);
                            }
                        }

                        var childrenToRemove = entity.Children
                            .Where(child => !processedKeys.Contains(child.SourceKey))
                            .ToList();
                        foreach (var child in childrenToRemove)
                        {
                            entity.Children.Remove(child);
                        }

                        entitiesToUpdate.Add(entity);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning(ex, $"[批量同步-物料清单] 修改实体失败，Id: {kvp.Key}");
                    }
                }
            }

            var updateCount = 0;
            var deleteCount = 0;
            if (entitiesToUpdate.Count > 0 || entitiesToDelete.Count > 0)
            {
                using (
                    var uow = UnitOfWorkManager.Begin(
                        new Volo.Abp.Uow.AbpUnitOfWorkOptions(),
                        requiresNew: true
                    )
                )
                {
                    try
                    {
                        if (entitiesToUpdate.Count > 0)
                        {
                            await BomMasterRepository.BulkUpdateAsync(
                                entitiesToUpdate,
                                autoSave: false
                            );
                            updateCount = entitiesToUpdate.Count;
                        }

                        if (entitiesToDelete.Count > 0)
                        {
                            await BomMasterRepository.BulkDeleteAsync(
                                entitiesToDelete,
                                autoSave: false
                            );
                            deleteCount = entitiesToDelete.Count;
                        }

                        await uow.CompleteAsync();
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning(ex, $"[批量同步-物料清单] 批量更新/删除失败，{ex.Message}");
                    }
                }
            }

            Logger.LogInformation($"[批量同步-物料清单] 完成！成功更新 {updateCount} 条");
            if (deleteCount > 0)
            {
                Logger.LogInformation($"[批量同步-物料清单] 删除 {deleteCount} 条记录");
            }

            return updateCount + deleteCount;
        }

        private BomMaster BuildBomMasterEntity(
            long masterId,
            List<BomMasterUfidaDto> items,
            Dictionary<string, ItemMasterDto> itemMasterCacheDict,
            Dictionary<Guid, UnitGroupDto> unitGroupCacheDict
        )
        {
            if (items == null || items.Count == 0)
                return null;

            if (
                !itemMasterCacheDict.TryGetValue(
                    items[0].MasterItemID.ToString(),
                    out var masterItemDto
                )
            )
            {
                Logger.LogWarning(
                    $"[批量同步-物料清单] 未找到母件料品，SourceKey: {items[0].MasterItemID}"
                );
                return null;
            }

            if (
                !TryGetAuxiliaryUnitId(
                    masterItemDto.UnitGroupId,
                    items[0].MasterUnit.ToString(),
                    unitGroupCacheDict,
                    out var masterUnitId
                )
            )
            {
                Logger.LogWarning(
                    $"[批量同步-物料清单] 未找到母件计量单位，SourceKey: {items[0].MasterUnit}"
                );
                return null;
            }

            var entityId = GuidGenerator.Create();
            var entity = new BomMaster
            {
                SourceType = SourceConfig.SourceType,
                SourceKey = masterId.ToString(),
                SourceCreatedOn = GetSourceCreatedOn(items),
                Code = items[0].MasterCode,
                BusinessDate = items[0].BusinessDate ?? DateTime.Now.Date,
                DocumentStatus = ToDocumentStatus(items[0].DocumentStatus),
                Version = items[0].Version,
                ItemMasterId = masterItemDto.Id,
                ItemCode = items[0].MasterCode,
                ItemName = items[0].MasterName,
                ItemSpec = items[0].MasterSPECS,
                UseCount = items[0].MasterUseCount,
                ParentCount = items[0].MasterUseCount,
                UnitId = masterUnitId,
                TenantId = CurrentTenant.Id,
                CreationTime = Clock.Now,
                CreatorId = CurrentUser.Id,
            };
            entity.SetId(entityId);

            foreach (var item in items)
            {
                if (
                    !itemMasterCacheDict.TryGetValue(
                        item.ComponentItemID.ToString(),
                        out var componentItemDto
                    )
                )
                {
                    Logger.LogWarning(
                        $"[批量同步-物料清单] 未找到子件料品，SourceKey: {item.ComponentItemID}"
                    );
                    return null;
                }

                if (
                    !TryGetAuxiliaryUnitId(
                        componentItemDto.UnitGroupId,
                        item.ComponentUnit.ToString(),
                        unitGroupCacheDict,
                        out var componentUnitId
                    )
                )
                {
                    Logger.LogWarning(
                        $"[批量同步-物料清单] 未找到子件计量单位，SourceKey: {item.ComponentUnit}"
                    );
                    return null;
                }

                var component = new BomComponent
                {
                    SourceType = SourceConfig.SourceType,
                    SourceKey = item.ComponentID.ToString(),
                    SourceCreatedOn = item.CreatedOn,
                    LineNo = item.Sequence,
                    ItemMasterId = componentItemDto.Id,
                    ItemCode = item.ComponentCode,
                    ItemName = item.ComponentName,
                    ItemSpec = item.ComponentSPECS,
                    UseCount = item.ComponentUseCount,
                    ParentCount = item.ComponentParentCount,
                    UnitId = componentUnitId,
                    DocumentId = entityId,
                    CreationTime = Clock.Now,
                    CreatorId = CurrentUser.Id,
                };
                component.SetId(GuidGenerator.Create());
                entity.Children.Add(component);
            }

            return entity;
        }

        private async Task<Dictionary<string, ItemMasterDto>> BatchLoadItemMasters(
            List<string> sourceKeys
        )
        {
            if (sourceKeys == null || sourceKeys.Count == 0)
                return new Dictionary<string, ItemMasterDto>();

            var query = await ItemMasterRepository.GetQueryableAsync();
            var items = await AsyncExecuter.ToListAsync(
                query.Where(x =>
                    sourceKeys.Contains(x.SourceKey) && x.SourceType == SourceConfig.SourceType
                )
            );

            return items.ToDictionary(
                x => x.SourceKey,
                x => ObjectMapper.Map<ItemMaster, ItemMasterDto>(x)
            );
        }

        private async Task<Dictionary<Guid, UnitGroupDto>> BatchLoadUnitGroups(
            List<Guid> unitGroupIds
        )
        {
            var result = new Dictionary<Guid, UnitGroupDto>();
            if (unitGroupIds == null || unitGroupIds.Count == 0)
            {
                return result;
            }

            foreach (var unitGroupId in unitGroupIds.Distinct())
            {
                try
                {
                    var dto = await UnitGroupAppService.GetAsync(unitGroupId);
                    result[unitGroupId] = dto;
                }
                catch (Exception ex)
                {
                    Logger.LogWarning(ex, $"批量加载单位组失败，UnitGroupId: {unitGroupId}");
                }
            }

            return result;
        }

        private bool TryGetAuxiliaryUnitId(
            Guid unitGroupId,
            string sourceKey,
            Dictionary<Guid, UnitGroupDto> unitGroupCacheDict,
            out Guid unitId
        )
        {
            unitId = Guid.Empty;
            if (!unitGroupCacheDict.TryGetValue(unitGroupId, out var unitGroupDto))
            {
                return false;
            }

            var unit = unitGroupDto.Children.FirstOrDefault(x =>
                x.SourceType == SourceConfig.SourceType && x.SourceKey == sourceKey
            );
            if (unit == null)
            {
                return false;
            }

            unitId = unit.Id;
            return true;
        }

        private DocumentStatus ToDocumentStatus(int status)
        {
            if (status == 0)
            {
                return DocumentStatus.Open;
            }

            if (status == 1)
            {
                return DocumentStatus.Waiting;
            }

            if (status == 2)
            {
                return DocumentStatus.Approved;
            }

            if (status == 3)
            {
                return DocumentStatus.Closed;
            }

            return DocumentStatus.Open;
        }

        private DateTime? GetSourceCreatedOn(IEnumerable<BomMasterUfidaDto> items)
        {
            return items
                .Where(x => x.CreatedOn.HasValue)
                .Select(x => x.CreatedOn)
                .OrderByDescending(x => x)
                .FirstOrDefault();
        }
    }
}
